package net.repchain.browser.common;

import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import net.repchain.browser.dao.RepchainBlockDao;
import net.repchain.browser.entity.ParsedTx;
import com.rcjava.client.ChainInfoClient;
import com.rcjava.exception.SyncBlockException;
import com.rcjava.protos.Peer;
import com.rcjava.sync.SyncInfo;
import com.rcjava.sync.SyncListener;
import com.rcjava.sync.SyncService;
import net.repchain.browser.entity.RepchainBlock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import tk.mybatis.mapper.entity.Example;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 区块同步服务
 *
 * @author zyf
 */
public class BlockSync implements SyncListener {


    private final Logger logger = LoggerFactory.getLogger(BlockSync.class);

    final RepchainConfig repchainConfig;
    final RepchainBlockDao repchainBlockDao;
    final BlockSyncService blockSyncService;

    public BlockSync(RepchainConfig repchainConfig,
                     BlockSyncService blockSyncService,
                     RepchainBlockDao repchainBlockDao) {
        this.repchainConfig = repchainConfig;
        this.repchainBlockDao = repchainBlockDao;
        this.blockSyncService = blockSyncService;
        this.syncBlock();
    }

    /**
     * 同步区块
     */
    private void syncBlock() {
        String host = repchainConfig.getHost();
        long locHeight = repchainConfig.getBlockHeight(); //从哪个区块开始同步，拟同步的区块高度的下限，在application.yml里配置
        // 获取最新区块高度
        //Map<String, Object> block = baseMapper.selectOneSql("SELECT BLOCK_HEIGHT FROM SG_OP_BLOCK ORDER BY BLOCK_HEIGHT DESC LIMIT 0,1");
        // 在实际使用中，持久化存储block，在BLOCK_HEIGHT中保存的已经同步到的区块高度，然后在这里查询得到block，能够实现程序重新运行能继续上次同步
        Long tempLocHeight = repchainBlockDao.getLastBlockInfo(); // 用于保存当前同步到的区块高度
        if (tempLocHeight != null ) {
            tempLocHeight =  Math.max(locHeight, tempLocHeight);
        } else {
            tempLocHeight = locHeight;
        }
        SyncInfo syncInfo;
        if (tempLocHeight == 0) {
            syncInfo = new SyncInfo(0, "");
        } else if (tempLocHeight > 0) {
            String locBlkHash = new ChainInfoClient(host).getBlockByHeight(tempLocHeight).getHeader().getHashPresent().toStringUtf8();
            syncInfo = new SyncInfo(tempLocHeight, locBlkHash);
        } else {
            logger.error("本地设置区块高度不能小于0");
            throw new RuntimeException("本地设置区块高度不能小于0");
        }
        SyncService syncService = SyncService.newBuilder().setHost(host).setSyncInfo(syncInfo).setSyncListener(this).build();
        Thread thread = new Thread(syncService::start, "SyncServiceThread");
        thread.start();
    }

    /**
     * 用于解析获取到的区块数据，对应RepChain上的接口/block/$idx返回的数据
     * 如需要得到链上数据，请修改此方法内部逻辑来进行解析、持久化到业务数据库
     *
     * @param block
     * @throws SyncBlockException
     */
    @Override
    public void onSuccess(Peer.Block block) throws SyncBlockException {
        try {
            blockSyncService.saveBlock(block);
        } catch (Exception ex) {
            throw new SyncBlockException(ex);
        }
    }

    @Override
    public void onError(SyncBlockException syncBlockException) {
        logger.error("同步区块出现错误：{}", syncBlockException.getMessage(), syncBlockException);
    }
}
